﻿/*    
    OpenMheg - A free MHEG-5 library
    Copyright (C) 2008 Dharmesh Malam

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Text;
using ASN1Decoder.Builders.Nodes;
using Core.Model.Actions;
using Core.Model;
using Core.Model.Actions.Elementary;
using Exceptions;
using Core.Model.Groups;
using Action = Core.Model.Actions.Action;
namespace ASN1Decoder.Builders
{
    internal class ActionBuilder
    {

        public static Action Build(ASN1Node node, Group group)
        {
            return Build((SequenceNode)node, group);
        }
        public static Action Build(SequenceNode node, Group group)
        {
            Action action = new Action();

            foreach (TaggedNode actionElement in node.Arguments )
            {
                action.ElementaryActions.Add(BuildElementaryAction(actionElement, group));

            }

            return action;
        }

        private static ElementaryAction BuildElementaryAction(TaggedNode node, Group group)
        {
            ElementaryAction ret = null;
            
            switch (node.Tag)
            {
                case (ASN1ContextCodes.C_ACTIVATE):
                    Activate activate = new Activate();
                    ret = activate;
                    break;

                case (ASN1ContextCodes.C_ADD):

                    Add add = new Add();
                    add.Operand = GenericVariableBuilder.BuildGenericInteger(node.Second,group);
                    ret = add;
                    break;

                case (ASN1ContextCodes.C_ADD_ITEM):
                    //AddItem addItem = new AddItem();
                    //ret = addItem;
                    break;

                case (ASN1ContextCodes.C_APPEND):
                    Append append = new Append();
                    append.String = GenericVariableBuilder.BuildGenericOctetString(node.Second, group);
                    ret = append;
                    break;

                case (ASN1ContextCodes.C_BRING_TO_FRONT):
                    BringToFront bringToFront = new BringToFront();
                    ret = bringToFront;
                    break;

                case (ASN1ContextCodes.C_CALL):
                    Call call = new Call();
                    call.CallSucceeded = ObjectRefBuilder.Build(node.Second, group);


                    foreach (TaggedNode parameter in (SequenceNode)node.Third)
                    {
                        call.Parameters.Add(GenericVariableBuilder.Build(parameter, group));
                    }

                    ret = call;
                    break;

                case (ASN1ContextCodes.C_CALL_ACTION_SLOT):
                    CallActionSlot callActionSlot = new CallActionSlot();
                    callActionSlot.Index = GenericVariableBuilder.BuildGenericInteger(node.Second, group);
                    ret = callActionSlot;
                    break;

                case (ASN1ContextCodes.C_CLEAR):
                    //Clear clear = new Clear();
                    //ret = clear;
                    break;

                case (ASN1ContextCodes.C_CLONE):

                    break;

                case (ASN1ContextCodes.C_DEACTIVATE):
                    Deactivate deactivate = new Deactivate();
                     ret = deactivate;
                    break;

                case (ASN1ContextCodes.C_DEL_ITEM):
                    //DelItem delItem = new DelItem();
                    //ret = delItem;
                    break;

                case (ASN1ContextCodes.C_DESELECT):
                    //not exists?
                    break;

                case (ASN1ContextCodes.C_DESELECT_ITEM):
                    //DeselectItem deselectItem = new DeselectItem();
                    //ret = deselectItem;
                    break;

                case (ASN1ContextCodes.C_DIVIDE):

                    Divide divide = new Divide();
                    divide.Operand = GenericVariableBuilder.BuildGenericInteger(node.Second, group);
                    ret = divide;

                    break;

                case (ASN1ContextCodes.C_DRAW_ARC):

                    break;
                case (ASN1ContextCodes.C_DRAW_LINE):

                    break;
                case (ASN1ContextCodes.C_DRAW_OVAL):

                    break;
                case (ASN1ContextCodes.C_DRAW_POLYGON):

                    break;
                case (ASN1ContextCodes.C_DRAW_POLYLINE):

                    break;
                case (ASN1ContextCodes.C_DRAW_RECTANGLE):
                    DrawRectangle drawRectangle = new DrawRectangle();
                    drawRectangle.X1 = GenericVariableBuilder.BuildGenericInteger(node.Second,group);
                    drawRectangle.Y1 = GenericVariableBuilder.BuildGenericInteger(node.Third,group);
                    drawRectangle.X2 = GenericVariableBuilder.BuildGenericInteger(node.Fourth,group);
                    drawRectangle.Y2 = GenericVariableBuilder.BuildGenericInteger(node.Fifth,group);
                    ret = drawRectangle;

                    break;
                case (ASN1ContextCodes.C_DRAW_SECTOR):

                    break;
                case (ASN1ContextCodes.C_FORK):
                    //Fork fork = new Fork();
                    //ret = fork;
                    break;

                case (ASN1ContextCodes.C_GET_AVAILABILITY_STATUS):

                    break;
                case (ASN1ContextCodes.C_GET_BOX_SIZE):

                    break;
                case (ASN1ContextCodes.C_GET_CELL_ITEM):

                    break;
                case (ASN1ContextCodes.C_GET_CURSOR_POSITION):

                    break;
                case (ASN1ContextCodes.C_GET_ENGINE_SUPPORT):
                    GetEngineSupport getEngineSupport = new GetEngineSupport();
                    getEngineSupport.Feature = GenericVariableBuilder.BuildGenericOctetString(node.Second, group);
                    getEngineSupport.Answer = ObjectRefBuilder.Build(node.Third, group);
                    ret = getEngineSupport;

                    break;
                case (ASN1ContextCodes.C_GET_ENTRY_POINT):

                    break;
                case (ASN1ContextCodes.C_GET_FILL_COLOUR):

                    break;
                case (ASN1ContextCodes.C_GET_FIRST_ITEM):

                    break;
                case (ASN1ContextCodes.C_GET_HIGHLIGHT_STATUS):

                    break;
                case (ASN1ContextCodes.C_GET_INTERACTION_STATUS):

                    break;
                case (ASN1ContextCodes.C_GET_ITEM_STATUS):

                    break;
                case (ASN1ContextCodes.C_GET_LABEL):

                    break;
                case (ASN1ContextCodes.C_GET_LAST_ANCHOR_FIRED):

                    break;
                case (ASN1ContextCodes.C_GET_LINE_COLOUR):

                    break;
                case (ASN1ContextCodes.C_GET_LINE_STYLE):

                    break;
                case (ASN1ContextCodes.C_GET_LINE_WIDTH):

                    break;
                case (ASN1ContextCodes.C_GET_LIST_ITEM):

                    break;
                case (ASN1ContextCodes.C_GET_LIST_SIZE):

                    break;
                case (ASN1ContextCodes.C_GET_OVERWRITE_MODE):

                    break;
                case (ASN1ContextCodes.C_GET_PORTION):
                    
                    break;
                case (ASN1ContextCodes.C_GET_POSITION):

                    break;
                case (ASN1ContextCodes.C_GET_RUNNING_STATUS):
                    GetRunningStatus getRunningStatus = new GetRunningStatus();
                    getRunningStatus.RunningStatus = ObjectRefBuilder.Build(node.Second, group);
                    ret = getRunningStatus;

                    break;
                case (ASN1ContextCodes.C_GET_SELECTION_STATUS):

                    break;
                case (ASN1ContextCodes.C_GET_SLIDER_VALUE):

                    break;
                case (ASN1ContextCodes.C_GET_TEXT_CONTENT):

                    break;
                case (ASN1ContextCodes.C_GET_TEXT_DATA):
                    GetTextData getTextData = new GetTextData();
                    getTextData.TextDataVar = ObjectRefBuilder.Build(node.Second, group);
                    ret = getTextData;
                    break;
                case (ASN1ContextCodes.C_GET_TOKEN_POSITION):

                    break;
                case (ASN1ContextCodes.C_GET_VOLUME):

                    break;
                case (ASN1ContextCodes.C_LAUNCH):
                    Launch launch = new Launch();
                    ret = launch;
                    break;
                case (ASN1ContextCodes.C_LOCK_SCREEN):

                    LockScreen lockScreen = new LockScreen();
                    ret = lockScreen;
                    break;

                case (ASN1ContextCodes.C_MODULO):
                    Modulo modulo = new Modulo();
                    modulo.Operand = GenericVariableBuilder.BuildGenericInteger(node.Second, group);
                    ret = modulo;

                    break;
                case (ASN1ContextCodes.C_MOVE):
                    Move move = new Move();
                    move.MovementId = GenericVariableBuilder.BuildGenericInteger(node.Second, group);
                    ret = move;

                    break;

                case (ASN1ContextCodes.C_MOVE_TO):
                    MoveTo moveTo = new MoveTo();
                    moveTo.Index = GenericVariableBuilder.BuildGenericInteger(node.Second, group);
                    ret = moveTo;
                    break;

                case (ASN1ContextCodes.C_MULTIPLY):

                    Multiply multiply = new Multiply();
                    multiply.Operand = GenericVariableBuilder.BuildGenericInteger(node.Second, group);
                    ret = multiply;
                    break;

                case (ASN1ContextCodes.C_PRELOAD):

                    Preload preload = new Preload();
                    ret = preload;
                    break;
                case (ASN1ContextCodes.C_PUT_BEFORE):
                    PutBefore putBefore = new PutBefore();
                    putBefore.Visible = GenericVariableBuilder.BuildGenericObjectRef(node.Second, group);
                    ret = putBefore;
                    break;
                case (ASN1ContextCodes.C_PUT_BEHIND):

                    PutBehind putBehind = new PutBehind();
                    putBehind.Visible = GenericVariableBuilder.BuildGenericObjectRef(node.Second, group);
                    ret = putBehind;

                    break;

                case (ASN1ContextCodes.C_QUIT):

                    Quit quit = new Quit();
                    ret = quit;
                    break;
                case (ASN1ContextCodes.C_READ_PERSISTENT):
                    ReadPersistent readPersistent = new ReadPersistent();
                    
                    readPersistent.ReadSucceeded = ObjectRefBuilder.Build(node.Second, group);

                    foreach (ASN1Node var in (SequenceNode) node.Third)
                    {
                        readPersistent.Variables.Add(ObjectRefBuilder.Build(var, group));

                    }

                    readPersistent.Input = GenericVariableBuilder.BuildGenericOctetString(node.Fourth, group);

                    ret = readPersistent;

                    break;
                case (ASN1ContextCodes.C_RUN):
                    RunAction run = new RunAction();
                    ret = run;
                    break;
                case (ASN1ContextCodes.C_SCALE_BITMAP):
                    ScaleBitmap scaleBitmap = new ScaleBitmap();
                    scaleBitmap.XScale = GenericVariableBuilder.BuildGenericInteger(node.Second, group);
                    scaleBitmap.YScale = GenericVariableBuilder.BuildGenericInteger(node.Third, group);

                    ret = scaleBitmap;
                    break;
                case (ASN1ContextCodes.C_SCALE_VIDEO):
                    ScaleVideo scaleVideo = new ScaleVideo();
                    scaleVideo.XScale = GenericVariableBuilder.BuildGenericInteger(node.Second, group);
                    scaleVideo.YScale = GenericVariableBuilder.BuildGenericInteger(node.Third, group);

                    ret = scaleVideo;
                    break;
                case (ASN1ContextCodes.C_SCROLL_ITEMS):

                    break;
                case (ASN1ContextCodes.C_SELECT):

                    //Select select = new Select();
                    //ret = select;

                    break;
                case (ASN1ContextCodes.C_SELECT_ITEM):

                    break;
                case (ASN1ContextCodes.C_SEND_EVENT):
                    SendEvent sendEvent = new SendEvent();
                    sendEvent.EventSource = GenericVariableBuilder.BuildGenericObjectRef(node.Second, group);
                    sendEvent.EventType =Core.Model.Events.Event.getEvent(node.Third.EnumValue);
                    sendEvent.EventData = GenericVariableBuilder.Build((TaggedNode)node.Fourth, group);
                    ret = sendEvent;
                    break;
                case (ASN1ContextCodes.C_SEND_TO_BACK):

                    SendToBack sendToBack = new SendToBack();
                    ret = sendToBack;
                    break;
                case (ASN1ContextCodes.C_SET_BOX_SIZE):
                    SetBoxSize setBoxSize = new SetBoxSize();
                    setBoxSize.Width = GenericVariableBuilder.BuildGenericInteger(node.Second, group);
                    setBoxSize.Height = GenericVariableBuilder.BuildGenericInteger(node.Third, group);
                    ret = setBoxSize;
                    break;
                case (ASN1ContextCodes.C_SET_CACHE_PRIORITY):

                    break;
                case (ASN1ContextCodes.C_SET_COUNTER_END_POSITION):

                    break;
                case (ASN1ContextCodes.C_SET_COUNTER_POSITION):

                    break;
                case (ASN1ContextCodes.C_SET_COUNTER_TRIGGER):

                    break;
                case (ASN1ContextCodes.C_SET_CURSOR_POSITION):

                    break;
                case (ASN1ContextCodes.C_SET_CURSOR_SHAPE):

                    break;
                case (ASN1ContextCodes.C_SET_DATA):
                    SetData setData = new SetData();

                    ASN1Node s = node.Second;
                    if (s is TaggedNode || s is OctetStringNode)
                        setData.NewIncludedContent = GenericVariableBuilder.BuildGenericOctetString(s, group);
                    else if (s is SequenceNode) // Referenced content
                        setData.NewReferencedContent = GenericVariableBuilder.BuildGenericContentRef(s, group);
                    else
                        throw new Exception("Unkown nodes in set_data");
                
                    ret = setData;
                    break;
                case (ASN1ContextCodes.C_SET_ENTRY_POINT):

                    break;
                case (ASN1ContextCodes.C_SET_FILL_COLOUR):

                    SetFillColour setFillColour = new SetFillColour();
                    setFillColour.FillColour = ColourBuilder.Build(node.Second, group);

                    ret = setFillColour;
                    break;

                case (ASN1ContextCodes.C_SET_FIRST_ITEM):

                    break;
                case (ASN1ContextCodes.C_SET_FONT_REF):

                    break;
                case (ASN1ContextCodes.C_SET_HIGHLIGHT_STATUS):

                    break;
                case (ASN1ContextCodes.C_SET_INPUT_REGISTER):
                    break;

                case (ASN1ContextCodes.C_SET_INTERACTION_STATUS):

                    break;
                case (ASN1ContextCodes.C_SET_LABEL):

                    break;
                case (ASN1ContextCodes.C_SET_LINE_COLOUR):
                    SetLineColour setLineColour = new SetLineColour();
                    setLineColour.LineColour = ColourBuilder.Build(node.Second, group);
                    ret = setLineColour;

                    break;
                case (ASN1ContextCodes.C_SET_LINE_STYLE):

                    break;
                case (ASN1ContextCodes.C_SET_LINE_WIDTH):

                    break;
                case (ASN1ContextCodes.C_SET_OVERWRITE_MODE):

                    break;
                case (ASN1ContextCodes.C_SET_PALETTE_REF):

                    break;
                case (ASN1ContextCodes.C_SET_PORTION):

                    break;

                case (ASN1ContextCodes.C_SET_POSITION):

                    SetPosition setPosition = new SetPosition();
                    setPosition.NewX = GenericVariableBuilder.BuildGenericInteger(node.Second,group);
                    setPosition.NewY = GenericVariableBuilder.BuildGenericInteger(node.Third,group);

                    ret = setPosition;
                    break;

                case (ASN1ContextCodes.C_SET_SLIDER_VALUE):

                    break;

                case (ASN1ContextCodes.C_SET_SPEED):

                    break;

                case (ASN1ContextCodes.C_SET_TIMER):

                    SetTimer setTimer = new SetTimer();
                    setTimer.TimerId = GenericVariableBuilder.BuildGenericInteger(node.Second,group);

                    if (node.Size > 2)
                    {
                        SequenceNode seq = (SequenceNode) node.Third;
                        setTimer.TimerValue = GenericVariableBuilder.BuildGenericInteger(seq.First, group);

                        if (seq.Size > 1)
                            setTimer.AbsoluteTime = GenericVariableBuilder.BuildGenericBoolean(seq.Second, group);
                    }
                    ret = setTimer;

                    break;

                case (ASN1ContextCodes.C_SET_TRANSPARENCY):

                    break;

                case (ASN1ContextCodes.C_SET_VARIABLE):

                    SetVariable setVariable = new SetVariable();
                    BuildActionParameter(setVariable, (TaggedNode)node.Second, group);
                    ret = setVariable;
                    break;

                case (ASN1ContextCodes.C_SET_VOLUME):

                    break;

                case (ASN1ContextCodes.C_SPAWN):

                    //Spawn spawn = new Spawn();
                     // ret = spawn;
                    
                    break;
                case (ASN1ContextCodes.C_STEP):

                    break;
                case (ASN1ContextCodes.C_STOP):
                    Stop stop = new Stop();
                    ret = stop;
                    break;

                case (ASN1ContextCodes.C_STORE_PERSISTENT):
                    StorePersistent storePersistent = new StorePersistent();
                    storePersistent.StoreSucceeded = ObjectRefBuilder.Build(node.Second, group);

                    foreach (ASN1Node var in (SequenceNode)node.Third)
                    {
                        storePersistent.Variables.Add(ObjectRefBuilder.Build(var,group));

                    }
                    storePersistent.Output = GenericVariableBuilder.BuildGenericOctetString(node.Fourth,group);
                    ret = storePersistent;

                    break;
                case (ASN1ContextCodes.C_SUBTRACT):

                    Subtract subtract = new Subtract();
                    subtract.Operand = GenericVariableBuilder.BuildGenericInteger(node.Second, group);

                    ret = subtract;

                    break;
                case (ASN1ContextCodes.C_TEST_VARIABLE):

                    TestVariable testVariable = new TestVariable();
                    testVariable.Operator = GenericVariableBuilder.BuildGenericInteger(node.Second,group);

                    BuildActionParameter(testVariable, (TaggedNode) node.Third, group);
                    ret = testVariable;

                    break;
                case (ASN1ContextCodes.C_TOGGLE):

                    //Toggle toggle = new Toggle();
                    //ret = toggle;

                    break;
                case (ASN1ContextCodes.C_TOGGLE_ITEM):

                    break;
                case (ASN1ContextCodes.C_TRANSITION_TO):

                    TransitionTo transitionTo = new TransitionTo();
                    //node["connection_tag_or_null"]
                    ret = transitionTo;

                    break;
                case (ASN1ContextCodes.C_UNLOAD):

                    Unload unload = new Unload();
                    ret = unload;
                    break;
                case (ASN1ContextCodes.C_UNLOCK_SCREEN):
                    UnlockScreen unlockScreen = new UnlockScreen();
                    ret = unlockScreen;
                    break;

                default:
                    ret = null;
                    break;
            }
                    
            if (ret != null)
            {
                ret.TargetRef = GenericVariableBuilder.BuildGenericObjectRef(node.First, group);
            }
            else
            {
                throw new OpenMhegException("Unkown Action : " + node.Tag);
            }

            return ret;
        }
        

        private static void BuildActionParameter(ParameterAction parameterAction, TaggedNode node, Group group)
        {
            switch (node.Tag)
            {
                case ASN1ContextCodes.C_NEW_GENERIC_BOOLEAN:
                    parameterAction.BoolVal = GenericVariableBuilder.BuildGenericBoolean(node.First,group);
                    break;

                case ASN1ContextCodes.C_NEW_GENERIC_INTEGER:
                    parameterAction.IntVal = GenericVariableBuilder.BuildGenericInteger(node.First, group);
                    break;

                case ASN1ContextCodes.C_NEW_GENERIC_OCTETSTRING:
                    parameterAction.StringVal= GenericVariableBuilder.BuildGenericOctetString(node.First, group);
                    break;

                case ASN1ContextCodes.C_NEW_GENERIC_OBJECT_REF:
                    parameterAction.ObjectRefVal = GenericVariableBuilder.BuildGenericObjectRef(node.First, group);
                    break;
                    
                case ASN1ContextCodes.C_NEW_GENERIC_CONTENT_REF:
                    parameterAction.ContentRefVal = GenericVariableBuilder.BuildGenericContentRef(node.First, group);
                    break;

                default:
                    throw new OpenMhegException("Unkown parameter");
                    break;
            }
        }
    }
}
